package com.atguigu.gmall.wms.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.exception.OrderException;
import com.atguigu.gmall.wms.vo.SkuLockVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.gmall.common.bean.PageResultVo;
import com.atguigu.gmall.common.bean.PageParamVo;

import com.atguigu.gmall.wms.mapper.WareSkuMapper;
import com.atguigu.gmall.wms.entity.WareSkuEntity;
import com.atguigu.gmall.wms.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuMapper, WareSkuEntity> implements WareSkuService {

    @Autowired
   private RedissonClient redissonClient;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    private static final String LOCK_PREFIX="stock:lock:";
    private static final String KEY_PREFIX="stock:ware:";


    @Override
    public PageResultVo queryPage(PageParamVo paramVo) {
        IPage<WareSkuEntity> page = this.page(
                paramVo.getPage(),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageResultVo(page);
    }

    @Override
    @Transactional
    //3.验库存和锁库存
    public List<SkuLockVo> checkAndLock(List<SkuLockVo> lockVos, String orderToken) {
        if (CollectionUtils.isEmpty(lockVos)) {
            throw new OrderException("您没有选中的商品。。。");
        }
        // 遍历所有商品，验库存并锁库存
        lockVos.forEach(SkuLockVo->{
            checkLock(SkuLockVo);
        });
        // 判断是否存在锁定失败的商品，如果存在，要解锁已经锁定成功的商品的库存
        boolean match = lockVos.stream().anyMatch(SkuLockVo -> !SkuLockVo.getLock());
        if(match){
            List<SkuLockVo> successLockVos = lockVos.stream().filter(SkuLockVo::getLock).collect(Collectors.toList());
            successLockVos.forEach(SkuLockVo->{
                baseMapper.unlock(SkuLockVo.getWareSkuId(),SkuLockVo.getCount());
            });
            //存在锁定失败的商品，解锁完后，给页面返回锁定信息lockVo.setLock()
            return lockVos;
        }
        //不存在锁定失败的商品,则能跳转到订单页,并把锁定库存信息缓存到redis，以方便将来超时未支付解锁库存，支付时减库存
        //orderToken订单号
        redisTemplate.opsForValue().set(KEY_PREFIX+orderToken, JSON.toJSONString(lockVos));
        // 验库存并锁库存成功之后，返回之前发送消息定时解锁库存
        this.rabbitTemplate.convertAndSend("ORDER_EXCHANGE", "stock.ttl", orderToken);

        // 锁定成功，返回null
        return null;
    }

    public void checkLock(SkuLockVo lockVo){
        Long skuId = lockVo.getSkuId();
        Integer count = lockVo.getCount();
        // 添加分布式锁，保证操作的原子性
        RLock lock = redissonClient.getFairLock(LOCK_PREFIX + skuId);
        lock.lock();

        try {
            //验库存：本质就是查询库存
            List<WareSkuEntity> wareSkuEntities= baseMapper.check(skuId,count);
            if (CollectionUtils.isEmpty(wareSkuEntities)) {
                lockVo.setLock(false);
                return;
            }
            // 锁库存：本质更新锁定库存的数量
            // TODO：从最近的仓库锁库存，这里我们取第一个仓库(因为需要大数据分析)
            WareSkuEntity wareSkuEntity = wareSkuEntities.get(0);
            if(baseMapper.lock(wareSkuEntity.getId(),count)==1){
                lockVo.setLock(true);
                //如果有库存锁定失败，那么所有库存都得回滚，所以得把锁定成功的库存id记录下来，好回滚
                lockVo.setWareSkuId(wareSkuEntity.getId());
            }else {
                lockVo.setLock(false);
            }

        } finally {
            lock.unlock();
        }


    }

}